# -*- coding:utf-8 -*-

"""
    批量上传zip包到７牛云，然后更新数据到服务器
    * zip包命名格式：    V05S74,V1SHZ1_1.23_2.01_20160525.zip
        SN号前6位代表不同设备类型（多个使用逗号连接）_待升级版本_此包版本_升级包打包时间.zip
    Usage:    python upload_files.py <filename | filepath>

    七牛账号：
        huangtao@idealsee.cn
        huangtao
"""

import os, sys, json, random, hashlib
import urllib, urllib2, requests

from qiniu import Auth, put_file, etag, urlsafe_base64_encode
import qiniu.config
from fileinput import filename

import logging

# 7牛云
ACCESS_KEY      = 'A7vB3qbo79ZmA7dWNJTbMjjt1UVtjjTYbQ8jeyee'
SECRET_KEY      = '_4JSKT44vZYyM1RS9KXobTZWpNqLy1sOKPb2wus_'
BUCKET_NAME     = 'simlens-fota'
DOWNLOAD_URLS   = [
                   'http://oacehw58j.bkt.clouddn.com/'
                   ]

#SERVER_URL      = 'http://localhost:8080'        # 服务更新地址
SERVER_URL       = 'http://fota.idealens.com'      # 服务更新地址
USERNAME        = 'idealsee'
PASSWORD        = 'idealsee2012'


def get_zip_files(file_path):
    """ 获取当前需要上传的zip包文件名
    """
    file_names = []
    for parent, dirnames, filenames in os.walk(file_path):
        for filename in filenames:
            if filename.endswith('.zip'):
                if check_filename(filename):
                    file_names.append(os.path.join(parent, filename))
    return file_names


def check_filename(filename):
    """ 校验文件名格式是否正确
    """
    l = filename[:-4].split('_')
    if len(l) != 4 or '' in l:
        print '\tERROR zip file name:', filename
        return False
    return True


def check_file_exists(filename):
    """ 校验文件是否已经在服务端存在
    """
    md5, _ = get_file_md5(filename)
    file_name = filename.split(os.path.sep)[-1]

    conn = requests.session()

    # conn.proxies = {'http': 'http://10.0.1.37:3128',
    #                'https': 'http://10.0.1.37:3128'}

    # 先登陆
    uri = '/login/?'
    params = {
        'username':   USERNAME,
        'password':   PASSWORD
    }
    url = SERVER_URL + uri + urllib.urlencode(params)
    r = conn.post(url)
    d = json.loads(r.content)
    if d['code'] != 0:
        return False, 'login error!'

    # 检查是佛存在
    uri = '/file/check_exits/?'
    params = {
        'md5':      md5,
        'filename': file_name
    }
    url = SERVER_URL + uri + urllib.urlencode(params)
    r = conn.get(url)
    d = json.loads(r.content)
    if d['code'] != 0:
        return False
    else:
        return True


def upload_files_2_qiniu(filename):
    """ 上传文件到７牛
    """

    q = Auth(ACCESS_KEY, SECRET_KEY)                # 构建鉴权对象
    key = filename.split(os.path.sep)[-1]           # 上传到七牛后保存的文件名
    token = q.upload_token(BUCKET_NAME, key, 3600)  # 生成上传 Token，可以指定过期时间等
    localfile = filename                            # 要上传文件的本地路径
    ret, info = put_file(token, key, localfile)

    if ret['key'] != key:
        print 'filename:', filename
        print 'ret:', ret, 'info:', info
        return False, 'key error!!'
    if ret['hash'] != etag(localfile):
        print 'filename:', filename
        print 'ret:', ret, 'info:', info
        return False, 'hash error!!'

    return True, 'ok'


def update_file_2_server(filename):
    """ 更新已经上传到７牛云的文件到服务端
    """
    if not os.path.isfile(filename):
        return False, 'file not exists!'
    
    conn = requests.session()

    # conn.proxies = {'http': 'http://10.0.1.37:3128',
    #                'https': 'http://10.0.1.37:3128'}
    
    # 先登陆
    uri = '/login/?'
    params = {
        'username':   USERNAME,
        'password':   PASSWORD
    }
    url = SERVER_URL + uri + urllib.urlencode(params)
    r = conn.post(url)
    d = json.loads(r.content)
    if d['code'] != 0:
        return False, 'login error!'
    
    # 上传更新文件数据
    md5, size = get_file_md5(filename)
    file_name = filename.split(os.path.sep)[-1]
    download_url = random.choice(DOWNLOAD_URLS) + file_name
    
    json_file = filename[:-3] + 'json'
    if not os.path.isfile(json_file):
        return False, 'json file not exists!'
    
    with open(json_file, 'r') as f:
        d = json.load(f, encoding='utf8')
        change_logs = '\n'.join(d['change_logs'])
        finger_point = d['finger_point']

    uri = '/file/update/?'
    datas = {
              'filename':       file_name,
              'size':           size,
              'md5':            md5,
              'change_logs':    change_logs,
              'finger_point':   finger_point,
              'download_url':   download_url
              }
    url = SERVER_URL + uri
    r = conn.post(url, data=json.dumps(datas))
    d = json.loads(r.content)
    if d['code'] != 0:
        return False, d['info']
    return True, 'update success!'


def get_file_md5(filename):
    """ 分片计算文件的md5
    """
    block_size = 1024 * 1024 * 5    # 5M分片计算
    m = hashlib.md5()
    size = 0
    with open(filename, 'rb') as f:
        while True:
            data = f.read(block_size)
            if not data:
                break
            m.update(data)
            size += len(data)
    return m.hexdigest().lower(), size


def main():
    if len(sys.argv) != 2:
        print '\n Usage:    python ', __file__, ' <filename | filepath>\n'
        exit(0)
    path = os.path.abspath(sys.argv[1])
    if os.path.isdir(path):
        filenames = get_zip_files(path) # 上传path路径下所有zip文件
    else:
        filenames = [path]              #　上传单个文件
    
    ERRORS = []
    print '\n\tUpload Files:\n'
    for index, filename in enumerate(filenames):
        print ''.join(['\t', str(index + 1), '. ', filename])

        if not check_file_exists(filename):
            ERRORS.append(filename)
            ERRORS.append('file already exists!')
            continue

        ret, info = upload_files_2_qiniu(filename)
        if not ret:
            ERRORS.append(filename)
            ERRORS.append(info)
            continue

        ret, info = update_file_2_server(filename)
        if not ret:
            ERRORS.append(filename)
            ERRORS.append(info)

    if len(ERRORS):
        print '\n\t', '*' * 100
        print '\n\tUpload Failed:\n'
        index = 1
        while ERRORS:
            print ''.join(['\t', str(index), '. ', ERRORS[0]])
            print '\t   result: ', ERRORS[1], '\n'
            index += 1
            ERRORS = ERRORS[2:]


if __name__ == '__main__':
    main()
